﻿using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using Microsoft.Win32;
using XSerialization.Generator;

namespace XCodeGenerator
{
    /// <summary>
    /// ViewModel for MainWindow (see MVVM Pattern)
    /// </summary>
    public class MainViewModel
    {
        /// <summary>
        /// Generate RaisePropertyChanged call in Property setters.
        /// </summary>
        public bool PropertyChanged
        {
            get { return _propertyChanged; }
            set
            {
                _propertyChanged = value;
                UpdateGeneralMetaInformations();
            }
        }

        /// <summary>
        /// Generate override Dispose Method in classes.
        /// </summary>
        public bool Dispose
        {
            get { return _dispose; }
            set
            {
                _dispose = value;
                UpdateGeneralMetaInformations();
            }
        }

        /// <summary>
        /// Default NameSpace
        /// </summary>
        public string NameSpace { get; set; }

        /// <summary>
        /// Default Directory
        /// </summary>
        public string Directory { get; set; }

        /// <summary>
        /// List of all XSD Files
        /// </summary>
        public IList<IXsdFile> XsdFiles { get; set; }

        /// <summary>
        /// Selected XSD File
        /// </summary>
        public IXsdFile SelectedXsdFile { get; set; }

        /// <summary>
        /// Start Command for UI Control
        /// </summary>
        public ICommand StartCommand
        {
            get { return _startCommand ?? (_startCommand = new CommandHandler(StartGeneration, true)); }
        }

        /// <summary>
        /// Add Command for UI Control
        /// </summary>
        public ICommand AddCommand
        {
            get { return _addCommand ?? (_addCommand = new CommandHandler(AddXsdFile, true)); }
        }

        /// <summary>
        /// Remove Command for UI Control
        /// </summary>
        public ICommand RemoveCommand
        {
            get { return _removeCommand ?? (_removeCommand = new CommandHandler(RemoveXsdFile, true)); }
        }

        /// <summary>
        /// Add Command for UI Control
        /// </summary>
        public ICommand AddUsingCommand
        {
            get { return _addUsingCommand ?? (_addUsingCommand = new CommandHandler(AddUsing, true)); }
        }

        /// <summary>
        /// Add Command for UI Control
        /// </summary>
        public ICommand AddInterfaceCommand
        {
            get { return _addInterfaceCommand ?? (_addInterfaceCommand = new CommandHandler(AddInterace, true)); }
        }

        /// <summary>
        /// Remove Command for UI Control
        /// </summary>
        public ICommand RemoveUsingCommand
        {
            get { return _removeUsingCommand ?? (_removeUsingCommand = new CommandHandler(RemoveUsing, true)); }
        }

        /// <summary>
        /// Remove Command for UI Control
        /// </summary>
        public ICommand RemoveInterfaceCommand
        {
            get { return _removeInterfaceCommand ?? (_removeInterfaceCommand = new CommandHandler(RemoveInterface, true)); }
        }

        private ICommand _startCommand;
        private ICommand _addCommand;
        private ICommand _removeCommand;
        private ICommand _addUsingCommand;
        private ICommand _addInterfaceCommand;
        private ICommand _removeUsingCommand;
        private ICommand _removeInterfaceCommand;
        private bool _propertyChanged;
        private bool _dispose;

        /// <summary>
        /// Default Constructor
        /// </summary>
        public MainViewModel()
        {
            System.Reflection.Assembly ass = System.Reflection.Assembly.GetExecutingAssembly();
            FileInfo appInfo = new FileInfo(ass.FullName);

            Directory = appInfo.DirectoryName;
            NameSpace = "XSerialization.Generated";
            PropertyChanged = true;
            Dispose = true;

            XsdFiles = new ObservableCollection<IXsdFile>();
        }

        private void UpdateGeneralMetaInformations()
        {
            if (XsdFiles == null) return;

            foreach (IXsdFile xsdFile in XsdFiles)
            {
                xsdFile.CodeMetaInfo.GeneratedDisposeMethod = Dispose;
                xsdFile.InterfaceMetaInfo.GeneratedDisposeMethod = Dispose;
                xsdFile.CodeMetaInfo.GeneratedRaisePropertyChanged = PropertyChanged;
                xsdFile.InterfaceMetaInfo.GeneratedRaisePropertyChanged = PropertyChanged;
            }
        }

        private void AddXsdFile(string parameter)
        {
            OpenFileDialog dialog = new OpenFileDialog();
            dialog.Title = "Add Xsd";
            dialog.Multiselect = true;
            dialog.DefaultExt = ".xsd";
            dialog.Filter = "Xsd File (.xsd)|*.xsd";

            bool? dialogResult = dialog.ShowDialog();
            if (dialogResult == true)
            {
                foreach (string fileName in dialog.FileNames)
                {
                    bool contains = XsdFiles.Any(xsdFile => xsdFile.Path == fileName);
                    if (!contains) XsdFiles.Add(new XsdFile(new FileInfo(fileName), Directory, NameSpace));
                }
            }
        }

        private void RemoveXsdFile(string parameter)
        {
            if (SelectedXsdFile == null) return;

            XsdFiles.Remove(SelectedXsdFile);
            SelectedXsdFile = null;
        }

        private void AddUsing(string parameter)
        {
            string inputText = GetInput();
            if (string.IsNullOrEmpty(inputText) || string.IsNullOrEmpty(parameter)) return;

            IFileMetaInfo metaInfo = GetMetaInfo(parameter);
            if (metaInfo == null) return;

            metaInfo.Usings.Add(inputText);
        }

        private void AddInterace(string parameter)
        {
            string inputText = GetInput();
            if (string.IsNullOrEmpty(inputText) || string.IsNullOrEmpty(parameter)) return;

            IFileMetaInfo metaInfo = GetMetaInfo(parameter);
            if (metaInfo == null) return;

            metaInfo.Interfaces.Add(inputText);
        }

        private void RemoveUsing(string parameter)
        {
            IFileMetaInfo metaInfo = GetMetaInfo(parameter);
            if (metaInfo == null) return;

            metaInfo.Usings.Remove(((FileMetaInfo) metaInfo).SelectedUsing);
        }

        private void RemoveInterface(string parameter)
        {
            IFileMetaInfo metaInfo = GetMetaInfo(parameter);
            if (metaInfo == null) return;

            metaInfo.Interfaces.Remove(((FileMetaInfo)metaInfo).SelectedInterface);
        }

        private string GetInput()
        {
            if (SelectedXsdFile == null) return null;

            InputBox inputBox = new InputBox();
            bool? dialogClosed = inputBox.ShowDialog();

            if (dialogClosed != true || string.IsNullOrEmpty(inputBox.InputText.Text)) return null;

            return inputBox.InputText.Text;
        }

        private IFileMetaInfo GetMetaInfo(string parameter)
        {
            switch (parameter)
            {
                case "Interface":
                    {
                        return SelectedXsdFile.InterfaceMetaInfo;
                        break;
                    }
                case "Code":
                    {
                        return SelectedXsdFile.CodeMetaInfo;
                        break;
                    }
            }

            return null;
        }

        private void StartGeneration(string parameter)
        {
            IXGenerator generator = new XGenerator();

            foreach (IXsdFile xsdFile in XsdFiles)
            {
                generator.AddFile(xsdFile.Path, xsdFile.InterfaceMetaInfo, xsdFile.CodeMetaInfo);
            }
            
            generator.Start();
            generator.Save();

            MessageBox.Show("Generation done!");
        }
    }
}
